package org.qydjk.common.util.wechat;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.qydjk.common.constant.RedisConstant;
import org.qydjk.common.constant.WechatConstant;
import org.qydjk.common.pojo.WechatUserinfo;
import org.qydjk.common.util.HttpsUtil;
import org.qydjk.common.util.MD5Util;
import org.qydjk.common.util.RedisTemplateUtil;
import org.qydjk.common.util.StringUtil;
import org.qydjk.common.vo.wechat.WechatTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;

/**
 * 公众平台通用接口工具类
 */
public class WechatUtil {
	private static final Log logger = LogFactory.getLog(WechatUtil.class);

	/**
	 * 生成微信菜单
	 * @param redisTemplateUtil
	 * @param menuJson
	 * @return
	 */
	public static String genMenu(RedisTemplateUtil redisTemplateUtil,String menuJson) {
		String token = WechatUtil.getAccessToken(redisTemplateUtil);
		String requestUrl = WechatConstant.CREARE_MENU_URL.replace("ACCESS_TOKEN", token);
		String res = HttpsUtil.httpRequest(requestUrl, "POST", menuJson);
		return res;
	}

	/**
	 * 生成永久专属二维码的图片链接
	 * @param redisTemplateUtil
	 * @param key
	 * @return
	 */
	public static String genPerpetualQrcodeUrl(RedisTemplateUtil redisTemplateUtil,String key) {
		JSONObject data = new JSONObject();
		JSONObject actionInfo1 = new JSONObject();
		actionInfo1.put("scene_str", key);

		JSONObject actionInfo = new JSONObject();
		actionInfo.put("scene", actionInfo1);

		data.put("action_name", "QR_LIMIT_STR_SCENE");
		data.put("action_info", actionInfo);

		String token = WechatUtil.getAccessToken(redisTemplateUtil);
		String requestUrl = WechatConstant.CREATE_QRCODE_TICKET_URL.replace("ACCESS_TOKEN", token);
		String res = HttpsUtil.httpRequest(requestUrl, "POST", data.toJSONString());
		JSONObject resObj = JSONObject.parseObject(res);
		String ticket = resObj.getString("ticket");
		String ticketStr = URLEncoder.encode(ticket);
		return WechatConstant.CREATE_QRCODE_URL.replace("TICKET", ticketStr);
	}

	/**
	 * 生成临时专属二维码的图片链接
	 * @param redisTemplateUtil
	 * @param key
	 * @return
	 */
	public static String genTemporaryQrcodeUrl(RedisTemplateUtil redisTemplateUtil,int expireSeconds,int key) {
		JSONObject data = new JSONObject();
		JSONObject actionInfo1 = new JSONObject();
		actionInfo1.put("scene_id", key);

		JSONObject actionInfo = new JSONObject();
		actionInfo.put("scene", actionInfo1);

		data.put("expire_seconds", expireSeconds);
		data.put("action_name", "QR_SCENE");
		data.put("action_info", actionInfo);

		String token = WechatUtil.getAccessToken(redisTemplateUtil);
		String requestUrl = WechatConstant.CREATE_QRCODE_TICKET_URL.replace("ACCESS_TOKEN", token);
		String res = HttpsUtil.httpRequest(requestUrl, "POST", data.toJSONString());
		JSONObject resObj = JSONObject.parseObject(res);
		String ticket = resObj.getString("ticket");
		String ticketStr = URLEncoder.encode(ticket);
		return WechatConstant.CREATE_QRCODE_URL.replace("TICKET", ticketStr);
	}

	/**
	 * 发送微信模板消息
	 *
	 * @param accessToken
	 * @param template
	 */
	public static void sendTemplateMessage(String accessToken, WechatTemplate template) {
		String requestUrl = WechatConstant.TEMPLATE_MESSAGE_URL.replace(
				"ACCESS_TOKEN", accessToken);
		HttpsUtil.httpRequest(requestUrl, "POST", JSONObject.toJSONString(template));
	}


	/**
	 * 判断是不是微信浏览器请求
	 * @param request
	 * @return
	 */
	public static Boolean isWechat(HttpServletRequest request){
		String ua = request.getHeader("user-agent").toLowerCase();
		if (ua.indexOf("micromessenger") > 0) {// 是微信浏览器
			return true;
		}
		return false;
	}

	/**
	 * 获取access_token
	 */
	public static String getAccessToken(RedisTemplateUtil redisTemplateUtil) {
		// 从缓存取access_token
		Map<String, String> map = (Map<String, String>) redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_ACCESS_TOKEN_KEY);
		String expiresInStr = "";
		String token = "";
		// 确保不是第一次
		if (map != null) {
			expiresInStr = map.get("expiresIn");
			token = map.get("token");
			if (!StringUtil.isEmptyOrNull(expiresInStr) && !StringUtil.isEmptyOrNull(token)) {
				long expiresInLong = Long.parseLong(expiresInStr);
				long currentTime = new Date().getTime();
				if (expiresInLong >= currentTime) {
					return token;
				}
			}
		}
		String requestUrl = WechatConstant.ACCESS_TOKEN_URL.replace("APPID",
				redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_APP_ID_KEY).toString()).replace("APPSECRET",
				redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_APP_SECRET_KEY).toString());
		String res = HttpsUtil.httpRequest(requestUrl, "GET", null);
		// 如果请求成功
		if (!StringUtil.isEmptyOrNull(res)) {
			JSONObject jsonObject = JSONObject.parseObject(res);
			token = jsonObject.getString("access_token");
			// 单位为秒
			long expiresIn = jsonObject.getLong("expires_in");
			// 即时毫秒数
			long currentTime = new Date().getTime();
			// 减掉60秒的误差，换算成毫秒，算出失效的时间
			expiresIn = (expiresIn - 60) * 1000;
			map = new HashMap<String, String>();
			map.put("token", token);
			map.put("expiresIn", "" + (currentTime + expiresIn));

			// 将access_token放入缓存
			redisTemplateUtil.setWithByte(RedisConstant.WECHAT_PUBLIC_ACCESS_TOKEN_KEY,map);
			return token;
		}
		return null;
	}

	/**
	 * 获取js_api
	 *
	 * @param accessToken
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String getJsApi(RedisTemplateUtil redisTemplateUtil,String accessToken) {
		// 从缓存取js_api
		Map<String, String> map = (Map<String, String>) redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_JS_API_KEY);
		String expiresInStr = "";
		String ticket = "";
		// 确保不是第一次
		if (map != null) {
			expiresInStr = map.get("expiresIn");
			ticket = map.get("ticket");
			if (!StringUtil.isEmptyOrNull(expiresInStr)
					&& !StringUtil.isEmptyOrNull(ticket)) {
				long expiresInLong = Long.parseLong(expiresInStr);
				long currentTime = new Date().getTime();
				if (expiresInLong >= currentTime) {
					return ticket;
				}
			}
		}

		String requestUrl = WechatConstant.JS_API_URL.replace("ACCESS_TOKEN",
				accessToken);
		String res = HttpsUtil.httpRequest(requestUrl, "GET", null);
		// 如果请求成功
		if (!StringUtil.isEmptyOrNull(res)) {
			JSONObject jsonObject = JSONObject.parseObject(res);
			ticket = jsonObject.getString("ticket");
			// 单位为秒
			long expiresIn = jsonObject.getLong("expires_in");
			// 即时毫秒数
			long currentTime = new Date().getTime();
			// 减掉60秒的误差，换算成毫秒，算出失效的时间
			expiresIn = (expiresIn - 60) * 1000;
			map = new HashMap<String, String>();
			map.put("ticket", ticket);
			map.put("expiresIn", "" + (currentTime + expiresIn));

			// 将access_token放入缓存
			redisTemplateUtil.setWithByte(RedisConstant.WECHAT_PUBLIC_JS_API_KEY,map);
			return ticket;
		}
		return null;
	}

	/**
	 * 根据code获取access_token和openid
	 *
	 * openid、access_token
	 *
	 * @param code
	 * @return
	 */
	public static JSONObject getOpenIDAndAccessToken(RedisTemplateUtil redisTemplateUtil,String code) {
		String requestUrl = WechatConstant.GET_OPENID_ACCESSTOKEN_URL
				.replace("APPID",
						redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_APP_ID_KEY).toString()).replace("APPSECRET",
						redisTemplateUtil.getWithByte(RedisConstant.WECHAT_PUBLIC_APP_SECRET_KEY).toString())
				.replace("CODE", code);
		String res = HttpsUtil.httpRequest(requestUrl, "GET", null);
		JSONObject jsonObject = JSONObject.parseObject(res);
		return jsonObject;
	}

	/**
	 * 获取用户信息
	 *
	 * @param redisTemplateUtil
	 * @param openID
	 * @return
	 */
	public static WechatUserinfo getUserInfo(RedisTemplateUtil redisTemplateUtil, String openID) {
		String accessToken = WechatUtil.getAccessToken(redisTemplateUtil);
		String requestUrl = WechatConstant.GET_USER_INFO_URL.replace("OPENID",
				openID).replace("ACCESS_TOKEN", accessToken);
		String res = HttpsUtil.httpRequest(requestUrl, "GET", null);
		WechatUserinfo userInfo = JSONObject.parseObject(res, WechatUserinfo.class);
		return userInfo;
	}

	/**
	 * 微信支付成功返回字符串构建
	 * @return
	 */
	public static String genSuccessResp(){
		StringBuffer sb=new StringBuffer();
		sb.append("<xml>");
		sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
		sb.append("<return_msg><![CDATA[OK]]></return_msg>");
		sb.append("</xml>");
		return sb.toString();
	}

	/**
	 * 输入流转XML
	 * @param in
	 * @return
	 */
	public static String getXMLFromStream(InputStream in){
		String xml=null;
		byte[] data=new byte[1024*10];
		int len=0;
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		try {
			while( (len=in.read(data)) !=-1 ){
				out.write(data, 0, len);
			}
			xml=out.toString("utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		}

		return xml;
	}

	/**
	 * XML转Map，简单的，子节点不能是对象
	 * @param xml
	 * @return
	 */
	public static Map<String,String> getParamMap(String xml){
		Map<String,String> map=new HashMap<String,String>();
		try {
			xml=xml.trim();
			Document doc= DocumentHelper.parseText(xml);
			Element root=doc.getRootElement();
			List<Element> list=root.elements();
			if(list!=null && !list.isEmpty()){
				for(Element ele:list){
					String value= ele.getTextTrim();
					if(!StringUtil.isEmptyOrNull(value)){
						map.put(ele.getName(),value);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 微信签名
	 * @param map
	 * @param wxKey
	 * @return
	 */
	public static String getSign(Map<String,String> map,String wxKey){
		StringBuffer sb=new StringBuffer();
		List<String> names=new ArrayList<String>();
		if(map!=null && !map.isEmpty()){
			for(String key:map.keySet()){
				if("sign".equals(key)) continue;
				names.add(key);
			}
		}
		Collections.sort(names);
		for(String name:names){
			sb.append("&"+name+"="+map.get(name));
		}
		return MD5Util.getMD5Str(sb.toString().substring(1), "&key="+wxKey).toUpperCase();
	}

	/**
	 * 获取预支付信息
	 * @param params
	 * @param wxKey
	 * @return
	 */
	public static Map<String,String> prePay(Map<String,String> params,String wxKey){
		Map<String,String> rs=null;
		try {
			StringBuffer sb=new StringBuffer();
			sb.append("<xml>");
			if(params!=null && !params.isEmpty()){
				for(String key:params.keySet()){
					sb.append("<")
							.append(key)
							.append(">")
							.append(params.get(key))
							.append("</")
							.append(key)
							.append(">");
				}
			}

			sb.append("<sign>").append(getSign(params,wxKey)).append("</sign>");
			sb.append("</xml>");
			System.out.println("req-xml:"+sb.toString());
			String resp = HttpsUtil.post(WechatConstant.WECHAT_PREPAY_URL, sb.toString(), "utf-8");
			System.out.println("resp-xml:");
			System.out.println(resp);
			rs=getParamMap(resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return rs;
	}

}